/************************************************************************
* wm_x11.c
* voxelands - 3d voxel world sandbox game
* Copyright (C) Lisa 'darkrose' Milne 2016 <lisa@ltmnet.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>
************************************************************************/

#include "common.h"
#define _WM_EXPOSE_ALL
#include "wm.h"

#ifdef WIN32

/* initialise the game window */
int wm_init()
{
	wm_data.isinit = 1;

	wm_data.lfps_i = 0;
	wm_data.lfps[0] = 0;
	wm_data.lfps[1] = 0;
	wm_data.lfps[2] = 0;
	wm_data.lfps[3] = 0;

	return wm_create();
}

/* exit the game window */
void wm_exit()
{
	wm_destroy();
}

/* create a window */
int wm_create()
{
	GLuint PixelFormat;
	WNDCLASS wc;
	DWORD dwExStyle;
	DWORD dwStyle;
	RECT WindowRect;

	wm_data.hDC = NULL;
	wm_data.hRC = NULL;
	wm_data.hWnd = NULL;

	WindowRect.left = (long)0;
	WindowRect.right = (long)wm_data.size.width;
	WindowRect.top = (long)0;
	WindowRect.bottom=(long)wm_data.size.height;

	wm_data.hInstance = GetModuleHandle(NULL);
	wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wc.lpfnWndProc = (WNDPROC)WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = wm_data.hInstance;
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = NULL;
	wc.lpszMenuName = NULL;
	wc.lpszClassName = "OpenGL";

	if (!RegisterClass(&wc)) {
		vlprintf(CN_ERROR "Failed To Register The Window Class");
		return 1;
	}

	if (wm_data.fullscreen) {
		DEVMODE dmScreenSettings;
		memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
		dmScreenSettings.dmSize = sizeof(dmScreenSettings);
		dmScreenSettings.dmPelsWidth = wm_data.size.width;
		dmScreenSettings.dmPelsHeight = wm_data.size.height;
		dmScreenSettings.dmBitsPerPel = 24;
		dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

		/* if fullscreen fails, switch to windowed mode */
		if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
			vlprintf(CN_WARN "Requested Fullscreen Mode Is Not Supported");
			wm_data.fullscreen = 0;
		}
	}

	if (wm_data.fullscreen) {
		dwExStyle = WS_EX_APPWINDOW;
		dwStyle = WS_POPUP;
	}else{
		dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
		dwStyle = (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU);
	}

	AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);

	wm_data.hWnd = CreateWindowEx(
		dwExStyle,
		"OpenGL",
		PACKAGE,
		dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
		0,
		0,
		WindowRect.right-WindowRect.left,
		WindowRect.bottom-WindowRect.top,
		NULL,
		NULL,
		wm_data.hInstance,
		NULL
	);
	if (!wm_data.hWnd) {
		wm_destroy();
		vlprintf(CN_ERROR "Window Creation Error");
		return 1;
	}

	static PIXELFORMATDESCRIPTOR pfd = {
		sizeof(PIXELFORMATDESCRIPTOR),
		1,
		PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
		PFD_TYPE_RGBA,
		32,
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		16,
		0,
		0,
		PFD_MAIN_PLANE,
		0,
		0,
		0,
		0
	};

	if (!(wm_data.hDC = GetDC(wm_data.hWnd))) {
		wm_destroy();
		vlprintf(CN_ERROR "Can't Create A GL Device Context");
		return 1;
	}

	if (!(PixelFormat = ChoosePixelFormat(wm_data.hDC,&pfd))) {
		wm_destroy();
		vlprintf(CN_ERROR "Can't Find A Suitable PixelFormat");
		return 1;
	}

	if (!SetPixelFormat(wm_data.hDC,PixelFormat,&pfd)) {
		wm_destroy();
		vlprintf(CN_ERROR "Can't Set The PixelFormat");
		return 1;
	}

	/* this should probably be modified so it creates a OpenGL 3.3 context */
	if (!(wm_data.hRC = wglCreateContext(wm_data.hDC))) {
		wm_destroy();
		vlprintf(CN_ERROR "Can't Create A GL Rendering Context");
		return 1;
	}

	if (!wglMakeCurrent(wm_data.hDC,wm_data.hRC)) {
		wm_destroy();
		vlprintf(CN_ERROR "Can't Activate The GL Rendering Context");
		return 1;
	}

	ShowWindow(wm_data.hWnd,SW_SHOW);
	SetForegroundWindow(wm_data.hWnd);
	SetFocus(wm_data.hWnd);

	if (1) {
		int major;
		int minor;
		glGetIntegerv(GL_MAJOR_VERSION, &major);
		glGetIntegerv(GL_MINOR_VERSION, &minor);

		vlprintf(CN_INFO "Direct Rendering: OpenGL %d.%d",major,minor);
	}

	/* MUST be done, else rendering gets messed up */
	render3d_set_projection_matrix();

	return 0;
}

/* resize the screen, fullscreen or windowed */
int wm_resize()
{
	/* MUST be done after a resize, else rendering gets messed up */
	render3d_set_projection_matrix();

	return 0;
}

/* flush graphics through and flip buffers */
int wm_update()
{
	glFlush();
	/* update the screen */
	SwapBuffers(wm_data.hDC);
	return 0;
}

/* destroy the current window */
void wm_destroy()
{
	if (wm_data.fullscreen)
		ChangeDisplaySettings(NULL,0);

	if (wm_data.hRC) {
		if (!wglMakeCurrent(NULL,NULL)) {
			vlprintf(CN_WARN "Release Of DC And RC Failed");
		}

		if (!wglDeleteContext(wm_data.hRC)) {
			vlprintf(CN_WARN "Release Rendering Context Failed");
		}
		wm_data.hRC = NULL;
	}

	if (wm_data.hDC && !ReleaseDC(wm_data.hWnd,wm_data.hDC)) {
		vlprintf(CN_WARN "Release Device Context Failed");
		wm_data.hDC = NULL;
	}

	if (wm_data.hWnd && !DestroyWindow(wm_data.hWnd)) {
		vlprintf(CN_WARN "Could Not Release hWnd");
		wm_data.hWnd = NULL;
	}

	if (!UnregisterClass("OpenGL",wm_data.hInstance)) {
		vlprintf(CN_WARN "Could Not Unregister Class");
		wm_data.hInstance = NULL;
	}
}

/* set fullscreen on/off */
void wm_toggle_fullscreen(int fs)
{
	if (fs == wm_data.fullscreen)
		return;

	if (!wm_data.isinit) {
		wm_data.fullscreen = fs;
		return;
	}
	wm_destroy();
	wm_data.fullscreen = fs;
	wm_create();
}

/* use file as a cursor texture */
void wm_cursor(char* file, int width, int height, int offset_x, int offset_y)
{
/* TODO: once the rest of the graphics are in, do it */
#ifdef DONT_DO_IT_FOR_FUCKS_SAKE
	if (!file) {
		if (!wm_data.cursor.mat)
			return;

		wm_data.cursor.mat = NULL;
		/* TODO: w32 wm_cursor */

		return;
	}

	wm_data.cursor.mat = mat_from_image(file);
	wm_data.cursor.w = width;
	wm_data.cursor.h = height;
	wm_data.cursor.x = offset_x;
	wm_data.cursor.y = offset_y;

	if (!wm_data.cursor.mat)
		return;
	/* TODO: w32 wm_cursor */
#endif
}

/* grab mouse */
void wm_grab()
{
	/* TODO: w32 wm_grab */
}

/* stop grabbing mouse */
void wm_ungrab()
{
	/* TODO: w32 wm_ungrab */
}

/* set window title */
void wm_title(char* title)
{
	if (title) {
		if (wm_data.title)
			free(wm_data.title);
		wm_data.title = strdup(title);
	}
	if (!wm_data.isinit)
		return;

	SetWindowText(wm_data.hWnd,wm_data.title);
}
#endif
